package org.lc.cmd.util;

import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.BiPredicate;
import java.util.function.Supplier;

public class CollectionUtil {
    public static <T> boolean isEmpty(Collection<T> collection) {
        return collection == null || collection.isEmpty();
    }

    public static <T> boolean isNotEmpty(List<T> collection) {
        return !isEmpty(collection);
    }

    public static <T> boolean isEmpty(T[] array) {
        return array == null || array.length == 0;
    }

    public static <T> boolean isNotEmpty(T[] array) {
        return !isEmpty(array);
    }

    public static <T> T getOrNull(List<T> list, int i) {
        if (isEmpty(list) || i >= list.size()) {
            return null;
        }
        return list.get(i);
    }

    @SafeVarargs
    public static <T> Set<T> newSet(T... items) {
        return new HashSet<>(Arrays.asList(items));
    }

    public static boolean isEmpty(char[] array) {
        return array == null || array.length == 0;
    }

    public static boolean isNotEmpty(char[] array) {
        return !isEmpty(array);
    }

    public static List<Character> toList(char[] array) {
        List<Character> list = new ArrayList<>(array.length);
        for (char c : array) {
            list.add(c);
        }
        return list;
    }

    public static <K, V> boolean isEmpty(Map<K, V> map) {
        return map == null || map.isEmpty();
    }

    @SuppressWarnings("unused")
    public static <K, V> boolean isNotEmpty(Map<K, V> map) {
        return !isEmpty(map);
    }

    public static <K, V> Map<K, V> filter(Map<K, V> source, BiPredicate<K, V> filter, Supplier<Map<K, V>> mapSupplier) {
        assert source != null;
        Map<K, V> map = mapSupplier.get();
        source.forEach((k, v) -> {
            if (filter.test(k, v)) {
                map.put(k, v);
            }
        });
        return map;
    }

    @SuppressWarnings("unused")
    public static <K, V> Map<K, V> filter(Map<K, V> source, BiPredicate<K, V> filter) {
        return filter(source, filter, HashMap::new);
    }

    public static <T> List<T> subList(List<T> list, int fromIndex) {
        return list.subList(fromIndex, list.size());
    }

    public static <T> T[] withOutItem(T[] array, int index) {
        if (index < 0 || index >= array.length) {
            return array;
        }

        @SuppressWarnings("unchecked")
        T[] arr = (T[]) Array.newInstance(array.getClass().getComponentType(), array.length - 1);

        System.arraycopy(array, 0, arr, 0, index);
        System.arraycopy(array, index + 1, arr, index, array.length - index - 1);

        return arr;
    }

}
